//****************************
//FAT.h
//ee_hqxaa, Hilda
//with reference to Zhang Qi Bo
//****************************

#ifndef __FAT_H__
#define __FAT_H__

#define F_CPU 7372800UL

#include<stdlib.h>
#include<avr/io.h>
#include<util/delay.h>

//define data type
#define CHAR char				//8bit signed char
#define	BYTE unsigned char		//8bit unsigned
#define WORD unsigned int		//16bit unsigned
#define DWORD unsigned long		//32bit unsigned

// external functions in SD read
extern BYTE SD_ReadSingleBlock(DWORD sector, BYTE* buffer);
extern DWORD SD_ReadCapacity(void);

// define constant
#define MSDOSFSROOT		0		// cluster 0 , root dir
#define	CLUST_FREE		0
#define MSDOSFSFREE		0
#define CLUST_FIRST		2		// first legal cluster #
#define	CLUST_RSRVD		0xfff6	// reserved range
#define	CLUST_BAD		0xfff7
#define	CLUST_EOFS		0xfff8
#define CLUST_EOFE		0xffff	// end of eof cluster



// read the information of Disk partition
// in total 16 bytes
struct partrecord			//16 bytes, record of this partition, one of psPart[] in partsector
{
	BYTE prIsActive;		//0x80: active partition
	BYTE prStartHead;		//starting head for partition
	WORD prStartCylSect;	//starting [cylinder, sector]=[15:6, 5:0]
	BYTE prPartType;		//partition type, system ID
	BYTE prEndHead;			//ending head
	WORD prEndCylSect;		//ending cylinder, sector[15:6, 5:0]
	DWORD prStartLBA;		//relative sectors, 1st LBA sector for this partition
	DWORD prSize;			//size for the partition, #sectors
};


struct partsector				// 64 bytes following BPB, in 0 sector
{
	CHAR psPartCode[512-64-2];	// to make partsector 512byte
	BYTE psPart[64];			// 4 partition records, each 16 bytes
	BYTE psBootSectSig0;		// signature bytes 0
	BYTE psBootSectSig1;		// signature bytes 1
//	#define BOOTSIG0	0x55
//	#define BOOTSIG1	0xaa
};




struct bootsector710		// 512 byte, notice the order
{
	BYTE bsJump[3];			//jumpBoot instr:  0xE9xxxx or 0xEBxx90
	CHAR bsOemName[8];		//OEM name and version: "MSWIN4.1" by default

	CHAR bsBPB[53];			//BIOS parameter block

	CHAR bsExt[26];			//Bootsector extension
	CHAR bsBootCode[418];	//to make bootsector 512 bytes
	BYTE bsBootSectSig2;	//boot sector signature byte 0x00
	BYTE bsBootSectSig3;	//0x00
	BYTE bsBootSectSig0;	//0x55
	BYTE bsBootSectSig1;	//0xAA
	#define BOOTSIG0		0x55
	#define BOOTSIG1		0xAA
	#define BOOTSIG2		0x00
	#define BOOTSIG3		0x00
};

struct bpb710				//BIOS
{
	WORD bpbBytesPerSec;		//1
	BYTE bpbSecPerClust;		//2
	WORD bpbResSectors;			//3 : #reserved sectors, 32
	BYTE bpbFATs;				//4 : total # of FATs, 2
	WORD bpbRootDirEnts;		//5 : #root directory entries FAT16, FAT32 = 0
	WORD bpbSectors;			//6 : total # of sectors for FAT16, FAT32 = 0
	BYTE bpbMedia;				//7 : 0xF0
	WORD bpbFATsecs;			//8 : sectors per FAT for FAT16, FAT32 = 0
	WORD bpbSecPerTrack;		//9 : sectors per track
	WORD bpbHeads;				//10
	DWORD bpbHiddenSecs;		//11 : #hidden sectors

// 3.3 compat ends here
	DWORD bpbHugeSectors;		//# of sectors if bpbSectors = 0, 32bit
// 5.0 compat ends here
	DWORD bpbBigFATsecs;		// bpbFATsecs for FAT32
	WORD bpbExtFlags;			// extended flags
	#define FATNUM		0xf
	#define FATMIRROR	0x80

	WORD bpbFSVers;				//file system version
	#define FSVERS		0		//if not 0, ignore this volume
	DWORD bpbRootClust;			//start cluster for root dir, 2
	WORD bpbFSInfo;				//#sectors of FSInfo, 1
	WORD bpbBackup;				//#backup of boot sectors, 0/6
	// another 12bytes reserved, ignored
};





// an entry record in directory, 32 bytes
struct direntry				// a dos directory entry
{
		BYTE		deName[8];      	// filename, blank filled
#define SLOT_EMPTY      0x00            // slot has never been used
#define SLOT_E5         0x05            // the real value is 0xE5
#define SLOT_DELETED    0xE5            // file in this slot deleted
#define SLOT_DIR		0x2E			// a directorymmm
		BYTE		deExtension[3]; 	// extension, blank filled
		BYTE		deAttributes;   	// file attributes
#define ATTR_NORMAL     0x00            // normal file
#define ATTR_READONLY   0x01            // file is readonly
#define ATTR_HIDDEN     0x02            // file is hidden
#define ATTR_SYSTEM     0x04            // file is a system file
#define ATTR_VOLUME     0x08            // entry is a volume label
#define ATTR_LONG_FILENAME	0x0F		// this is a long filename entry
#define ATTR_DIRECTORY  0x10            // entry is a directory name
#define ATTR_ARCHIVE    0x20            // file is new or modified
		BYTE        deLowerCase;    	// NT VFAT lower case flags  (set to 0)
#define LCASE_BASE      0x08            // filename base in lower case
#define LCASE_EXT       0x10            // filename extension in lower case
		BYTE        deCHundredth;   	// hundredth of seconds in CTime
		BYTE        deCTime[2];     	// create time
		BYTE        deCDate[2];     	// create date
		BYTE        deADate[2];     	// access date
		WORD        deHighClust; 		// high bytes of cluster number
		BYTE        deMTime[2];     	// last update time
		BYTE        deMDate[2];     	// last update date
		WORD        deStartCluster; 	// starting cluster of file
		DWORD       deFileSize;  		// size of file in bytes

};


// when bpbBytesPerSec = 512 = 32 * 16
//define number of dir entries in one sector
#define DIRENTRIES_PER_SECTOR 0x10




// copy useful information from direntry to fileinfostruct
// 15 bytes
struct FileInfoStruct
{
	DWORD StartCluster;				//file starting cluster for last file accessed
	DWORD Size;						//file size for last file accessed
	BYTE  Attr;						//file attribute
	DWORD Sector;					//file record place
	WORD  Offset;					//file record offset
};









//functions that can be accessed by the external

extern BYTE		FAT_Init(void);
extern DWORD	FAT_NextCluster(DWORD cluster);
//extern WORD		FAT_FindItem(DWORD cluster, BYTE *name, struct FileInfoStruct *FileInfo);
extern DWORD	FAT_OpenDir(BYTE *dir);
extern BYTE		search(BYTE *dir, struct direntry *MusicInfo, BYTE *count, BYTE *type);
extern BYTE		FAT_LoadPartCluster(DWORD cluster, unsigned part, BYTE *buffer);

//=========this is for debug only===========
/*extern DWORD FirstFATSector;
extern DWORD FirstDirSector;
extern DWORD FirstDataSector;
extern BYTE (*FAT_ReadSector)(DWORD sector, BYTE * buffer);
*/
#endif
